package com.vaadin.thomas.contenttool.ui;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;

import com.vaadin.data.Item;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.util.HierarchicalContainer;
import com.vaadin.thomas.contenttool.data.Model;
import com.vaadin.thomas.contenttool.data.Tag;
import com.vaadin.thomas.contenttool.data.Value;
import com.vaadin.thomas.contenttool.ui.events.LangChangedEvent;
import com.vaadin.thomas.contenttool.ui.events.LangChangedListener;
import com.vaadin.thomas.contenttool.ui.events.MenuFilterEvent;
import com.vaadin.thomas.contenttool.ui.events.MenuFilterListener;
import com.vaadin.thomas.contenttool.ui.events.MenuFragmentSelectedEvent;
import com.vaadin.thomas.contenttool.ui.events.MenuTagSelectedEvent;
import com.vaadin.thomas.contenttool.ui.events.PreviewCommittedEvent;
import com.vaadin.thomas.contenttool.ui.events.PreviewCommittedListener;
import com.vaadin.thomas.contenttool.ui.events.TagsChangedEvent;
import com.vaadin.thomas.contenttool.ui.events.TagsChangedListener;
import com.vaadin.thomas.contenttool.ui.events.ValueAddedEvent;
import com.vaadin.thomas.contenttool.ui.events.ValueAddedListener;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.TabSheet.SelectedTabChangeEvent;
import com.vaadin.ui.Tree;
import com.vaadin.ui.Tree.ItemStyleGenerator;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.Reindeer;

public class MenuLayout extends VerticalLayout implements LangChangedListener,
		PreviewCommittedListener, MenuFilterListener, ValueAddedListener,
		TagsChangedListener {

	private static final long serialVersionUID = -2507824369753405573L;

	private static final String PROPID_CAPTION = "caption";

	private MenuFilter filterField;
	private TabSheet tabs;
	private Button add;
	private Button remove;
	private Tree valueTree;
	private Tree tagTree;

	public MenuLayout() {

		setSizeFull();
		addStyleName("menu");

		tabs = new TabSheet();
		tabs.setSizeFull();
		tabs.addStyleName(Reindeer.TABSHEET_MINIMAL);
		addComponent(tabs);
		setExpandRatio(tabs, 1);

		valueTree = new Tree();
		buildValueTab();
		tabs.addTab(valueTree,
				MainLayout.ct().get("contenttool.menu.id.caption"));

		if (MainLayout.ct().conf().allowTags()) {
			tagTree = new Tree();
			buildTagsTab();
			tabs.addTab(tagTree,
					MainLayout.ct().get("contenttool.menu.tag.caption"));
		}

		tabs.addListener(new TabSheet.SelectedTabChangeListener() {

			private static final long serialVersionUID = -3704531204409558315L;

			@Override
			public void selectedTabChange(SelectedTabChangeEvent event) {
				boolean isValueTab = tabs.getSelectedTab() == valueTree;
				add.setVisible(isValueTab);
				remove.setVisible(isValueTab);
			}
		});

		filterField = new MenuFilter();
		addComponent(filterField);

		HorizontalLayout hl = new HorizontalLayout();
		hl.setWidth(100, UNITS_PERCENTAGE);
		add = new Button();
		add.setWidth(100, UNITS_PERCENTAGE);
		add.addListener(new NewItemClickListener());
		hl.addComponent(add);

		remove = new Button();
		remove.setWidth(100, UNITS_PERCENTAGE);
		remove.addListener(new removeItemClickListener());
		hl.addComponent(remove);

		addComponent(hl);

		langChanged(null);

		MainLayout.bb().addListener(this);
	}

	private void buildValueTab() {

		valueTree.setContainerDataSource(new HierarchicalContainer());
		valueTree.addContainerProperty(PROPID_CAPTION, String.class, "");
		valueTree.setItemCaptionPropertyId(PROPID_CAPTION);

		List<Value> vals = new LinkedList<Value>(Model.get().getPreview()
				.getAllValues().values());

		Util.filterCTIdentifiers(vals, MainLayout.ct().conf()
				.showContentToolIdentifiers());

		Collections.sort(vals);
		for (Value v : vals) {

			StringTokenizer st = new StringTokenizer(v.getId(), ".");
			String last = null;
			while (true) {

				String subSection = st.nextToken();
				if (!st.hasMoreTokens()) {
					// last part, skip
					break;
				}
				if (!valueTree.containsId(subSection)) {
					valueTree.addItem(subSection)
							.getItemProperty(PROPID_CAPTION)
							.setValue(subSection);
					valueTree.setParent(subSection, last);
				}
				last = subSection;
			}

			Item i = valueTree.addItem(v);
			i.getItemProperty(PROPID_CAPTION).setValue(v.getId());

			valueTree.setParent(v, last);
		}

		for (Object o : valueTree.getContainerDataSource().getItemIds()) {
			if (!valueTree.hasChildren(o)) {
				valueTree.setChildrenAllowed(o, false);
			}

			valueTree.expandItem(o);
		}

		valueTree.addListener(new ValueTreeItemListener());
		valueTree.setImmediate(true);

		valueTree.setItemStyleGenerator(new ValueTreeStyleGenerator());

	}

	private void buildTagsTab() {
		if (!MainLayout.ct().conf().allowTags()) {
			return;
		}
		tagTree.setContainerDataSource(new HierarchicalContainer());
		tagTree.addContainerProperty(PROPID_CAPTION, String.class, "");
		tagTree.setItemCaptionPropertyId(PROPID_CAPTION);

		List<Tag> tags = new LinkedList<Tag>(Model.get().getTags());
		Collections.sort(tags);
		Object root = new Object();
		Item i = tagTree.addItem(root);
		i.getItemProperty(PROPID_CAPTION).setValue(
				MainLayout.ct().get("contenttool.content.item.tags_caption"));
		for (Tag t : tags) {

			i = tagTree.addItem(t);
			i.getItemProperty(PROPID_CAPTION).setValue(t.getValue());

			tagTree.setParent(t, root);
		}

		for (Object o : tagTree.getContainerDataSource().getItemIds()) {
			if (!tagTree.hasChildren(o)) {
				tagTree.setChildrenAllowed(o, false);
			}

			tagTree.expandItem(o);
		}

		tagTree.addListener(new TagTreeItemListener());
		tagTree.setImmediate(true);

	}

	@Override
	public void langChanged(LangChangedEvent event) {
		add.setCaption(MainLayout.ct().get("contenttool.menu.add"));
		remove.setCaption(MainLayout.ct().get("contenttool.menu.remove"));

		tabs.getTab(valueTree).setCaption(
				MainLayout.ct().get("contenttool.menu.id.caption"));
	}

	private static class ValueTreeItemListener implements ValueChangeListener {

		private static final long serialVersionUID = -6857561491318045026L;

		@Override
		public void valueChange(ValueChangeEvent event) {

			Object val = event.getProperty().getValue();
			Tree tree = (Tree) event.getProperty();

			String fragment;
			if (val == null) {
				fragment = null;

			} else if (val instanceof String) {

				fragment = (String) val;
				while (tree.getParent(val) != null) {
					val = tree.getParent(val);
					fragment = val + "." + fragment;
				}

			} else {
				Value v = (Value) val;
				fragment = v.getId();
			}

			MainLayout.bb().fire(new MenuFragmentSelectedEvent(fragment));
		}
	}

	private static class TagTreeItemListener implements ValueChangeListener {

		private static final long serialVersionUID = -6857561491318045026L;

		@Override
		public void valueChange(ValueChangeEvent event) {

			Object val = event.getProperty().getValue();

			Tag t = null;
			if (val instanceof Tag) {
				t = (Tag) val;
			}
			MainLayout.bb().fire(new MenuTagSelectedEvent(t));

		}
	}

	private class NewItemClickListener implements ClickListener {

		private static final long serialVersionUID = 8768022177503130771L;

		@Override
		public void buttonClick(ClickEvent event) {

			String fragment;
			if (valueTree.getValue() == null) {
				fragment = "";
			} else if (valueTree.getValue() instanceof Value) {
				fragment = ((Value) valueTree.getValue()).getId();
			} else {

				fragment = "";
				Object o = valueTree.getValue();
				while (valueTree.getParent(o) != null) {
					fragment = o + "." + fragment;
					o = valueTree.getParent(o);
				}
			}
			event.getButton()
					.getWindow()
					.addWindow(
							new AddValueWindow(fragment,
									valueTree.getValue() instanceof Value));
		}
	}

	private class removeItemClickListener implements ClickListener {

		private static final long serialVersionUID = 8404660167922033932L;

		@Override
		public void buttonClick(ClickEvent event) {

			if (valueTree.getValue() instanceof Value) {
				Value selected = (Value) valueTree.getValue();
				Model.get().addValue(selected.getId()).markForDelete();

				valueTree.setItemStyleGenerator(new ValueTreeStyleGenerator());
				valueTree.requestRepaint();

				MainLayout.bb().fire(
						new MenuFragmentSelectedEvent(selected.getId()));
			}
		}
	}

	public class ValueTreeStyleGenerator implements ItemStyleGenerator {

		private static final long serialVersionUID = 4581269947594850658L;

		@Override
		public String getStyle(Object itemId) {

			if (itemId instanceof Value) {
				if (((Value) itemId).isDeleted()) {
					return "deleted";
				}
			}
			return null;
		}
	}

	@Override
	public void previewCommited(PreviewCommittedEvent event) {
		buildValueTab();
		buildTagsTab();
	}

	@Override
	public void filterChanged(final MenuFilterEvent event) {
		HierarchicalContainer valueCont = (HierarchicalContainer) valueTree
				.getContainerDataSource();
		valueCont.removeAllContainerFilters();

		HierarchicalContainer tagCont = (HierarchicalContainer) tagTree
				.getContainerDataSource();
		tagCont.removeAllContainerFilters();

		if (event.getIdFragment() == null || event.getIdFragment().equals("")) {
			return;
		}

		valueCont.addContainerFilter(PROPID_CAPTION, event.getIdFragment(),
				true, false);
		tagCont.addContainerFilter(PROPID_CAPTION, event.getIdFragment(), true,
				false);
	}

	@Override
	public void valueAdded(ValueAddedEvent event) {
		buildValueTab();
		valueTree.select(event.getValue());
	}

	@Override
	public void tagsChanged(TagsChangedEvent event) {
		Object selected = tagTree == null ? null : tagTree.getValue();
		buildTagsTab();
		tagTree.setValue(selected);
	}
}
